#include <stdio.h>
#include "startlvgl.h"
#include "esp_log.h"
#include "esp_event.h"
#include "esp_timer.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/semphr.h"

#include "esp_lcd_ili9341.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"

#include "driver/spi_master.h"
#include "lvgl.h"
#include "lvgl_helpers.h"

lv_indev_t *touch_pad;
SemaphoreHandle_t xGuiSemaphore;
esp_lcd_panel_handle_t panel_handle;

static void lv_tick_task(void *arg)
{
    lv_tick_inc(LV_TICK_PERIOD_MS);
}

static void guiTask(void *pvParameter)
{

    while (1)
    {
        /* Delay 1 tick (assumes FreeRTOS tick is 10ms */
        vTaskDelay(pdMS_TO_TICKS(10));

        /* Try to take the semaphore, call lvgl related function on success */
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY))
        {
            lv_task_handler();
            xSemaphoreGive(xGuiSemaphore);
        }
    }
}

void init_spi_bus()
{
    spi_bus_config_t buscfg = {
        .sclk_io_num = PIN_LCD_CLK,
        .mosi_io_num = PIN_LCD_MOSI,
        .miso_io_num = PIN_LCD_MISO,
        .quadwp_io_num = -1,                                    // Quad SPI LCD driver is not yet supported
        .quadhd_io_num = -1,                                    // Quad SPI LCD driver is not yet supported
        .max_transfer_sz = LCD_HOR * 40 * 3 * sizeof(uint16_t), // transfer 80 lines of pixels (assume pixel is RGB565) at most in one SPI transaction
    };

    ESP_ERROR_CHECK(spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); // Enable the DMA feature
}

bool call_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_disp_flush_ready(&(_lv_refr_get_disp_refreshing())->driver);
    return false;
}


void add_dsp_on_spi_bus()
{
    esp_lcd_panel_io_handle_t io_handle = NULL; // 创建LCD IO句柄
    // IO配置
    esp_lcd_panel_io_spi_config_t io_config = {

        .dc_gpio_num = PIN_LCD_DC,
        .cs_gpio_num = PIN_LCD_CS,
        .pclk_hz = SPI_SPEED,
        .lcd_cmd_bits = 8,       // CMD命令长度
        .lcd_param_bits = 8,     // 命令单个参数长度
        .spi_mode = 0,           // 传输模式  0:主机模式   1:从机模式
        .trans_queue_depth = 10, // 传输队列大小（就是能有几个传输任务排队）
        .on_color_trans_done = call_lvgl_flush_ready,
        // .user_ctx = &disp_drv,
    };

    // 添加LCD IO到SPI
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI_LCD_HOST, &io_config, &io_handle));

    // esp_lcd_panel_handle_t panel_handle = NULL; // 创建屏幕
    // 屏幕配置
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_LCD_RST,
        .rgb_endian = LCD_RGB_ENDIAN_RGB, // 颜色输出模式（RGB/BGR）
        .bits_per_pixel = 16,             // 单个像素大小（RGB565）
        .flags.reset_active_high = 0,
    };

    ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle)); // 创建屏幕
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));                                  // 重启
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));                                  // 初始化
    // ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle,10,15));
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, 1));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, 0, 0)); // 镜像翻转
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
}

static void ili_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
    // esp_lcd_panel_handle_t panel_handlee = (esp_lcd_panel_handle_t) drv->user_data;
    int offsetx1 = area->x1;
    int offsetx2 = area->x2;
    int offsety1 = area->y1;
    int offsety2 = area->y2;
    // copy a buffer's content to a specific area of the display
    esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2, offsety2, color_map);
}

void init_lvgl()
{

    xGuiSemaphore = xSemaphoreCreateMutex();

    lv_init();
    init_spi_bus();
    add_dsp_on_spi_bus();
    // 初始化屏幕驱动
    //  lvgl_driver_init();

    lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1 != NULL);
#if 1
    lv_color_t *buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf2 != NULL);
#else
    lv_color_t *buf2 = NULL;
#endif

    static lv_disp_buf_t disp_buf;

    /* 初始化显示缓冲区。 */
    lv_disp_buf_init(&disp_buf, buf1, buf2, DISP_BUF_SIZE);

    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.flush_cb = ili_flush;

    /* 当设置黑白屏时需要这个玩意:
     * - rounder_cb
     * - set_px_cb */
    // disp_drv.rounder_cb = disp_driver_rounder;
    // disp_drv.set_px_cb = disp_driver_set_px;

    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /* 创建并启动周期性定时器中断，以调用lv_tick_inc */
    const esp_timer_create_args_t periodic_timer_args = {
        .callback = &lv_tick_task,
        .name = "periodic_gui"};
    esp_timer_handle_t periodic_timer;
    ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));

    xTaskCreatePinnedToCore(guiTask, "gui", 1024 * 4, NULL, 0, NULL, 1);

#if 0
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touch_driver_read;
    touch_pad = lv_indev_drv_register(&indev_drv);
#endif
}
